package net.cyue.web.easyquery.core.http.data;

import net.cyue.util.StringUtil;

import java.net.URLDecoder;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

/**
 * HTTP API 路径信息
 * <p>
 * 用于解析和匹配HTTP请求路径，支持路径参数和查询参数的提取。
 * 支持必需参数（如 {id}）和可选参数（如 {optional?}）。
 * </p>
 */
public class PathInfo {

    // 用于匹配花括号参数的正则表达式
    private static final Pattern PARAM_PATTERN = Pattern.compile("\\{([^}]+)}");

    // 用于匹配可选参数的正则表达式 {param?}
    private static final Pattern OPTIONAL_PARAM_PATTERN = Pattern.compile("\\{([^}]+)\\?}");

    private String contextPath;
    private final String apiPath;
    private final List<String> pathParameterList;
    private final List<String> optionalPathParameterList; // 可选路径参数
    private final Map<String, QueryParameter> queryParameterMap;
    private final Pattern pathPattern;
    private final boolean hasOptionalParams; // 是否包含可选参数

    /**
     * 创建一个 PathInfo 对象
     */
    private PathInfo(
        String contextPath,
        String apiPath,
        List<String> pathParameterList,
        List<String> optionalPathParameterList,
        Map<String, QueryParameter> queryParameterMap,
        Pattern pathPattern,
        boolean hasOptionalParams
    ) {
        this.setContextPath(contextPath);
        this.apiPath = normalizeURLPath(apiPath);
        this.pathParameterList = Collections.unmodifiableList(
            pathParameterList == null ? new ArrayList<>() : new ArrayList<>(pathParameterList)
        );
        this.optionalPathParameterList = Collections.unmodifiableList(
            optionalPathParameterList == null ? new ArrayList<>() : new ArrayList<>(optionalPathParameterList)
        );
        this.queryParameterMap = Collections.unmodifiableMap(
            queryParameterMap == null ? new HashMap<>() : new HashMap<>(queryParameterMap)
        );
        this.pathPattern = pathPattern;
        this.hasOptionalParams = hasOptionalParams;
    }

    /**
     * 从API路径创建一个 PathInfo 对象
     */
    public static PathInfo fromAPIPath(String apiPath) {
        return fromAPIPath(apiPath, ""); // 默认上下文路径为空
    }

    /**
     * 从API路径和上下文路径创建一个 PathInfo 对象
     */
    public static PathInfo fromAPIPath(String apiPath, String contextPath) {
        return fromAPIPath(apiPath, contextPath, new ArrayList<>());
    }

    /**
     * 从API路径、上下文路径和查询参数列表创建一个 PathInfo 对象
     */
    public static PathInfo fromAPIPath(String apiPath, String contextPath, String... queryParameterNames) {
        return fromAPIPath(
            apiPath,
            contextPath,
            Arrays.stream(queryParameterNames)
                .map(QueryParameter::new)
                .collect(Collectors.toList())
        );
    }

    /**
     * 从API路径、上下文路径和查询参数列表创建一个 PathInfo 对象
     */
    public static PathInfo fromAPIPath(String apiPath, String contextPath, QueryParameter... queryParameters) {
        return fromAPIPath(
            apiPath,
            contextPath,
            Arrays.asList(queryParameters)
        );
    }

    /**
     * 从API路径、上下文路径和查询参数列表创建一个 PathInfo 对象
     */
    public static PathInfo fromAPIPath(
        String apiPath,
        String contextPath,
        List<QueryParameter> queryParameterList
    ) {
        if (apiPath == null) {
            throw new IllegalArgumentException("API path cannot be null");
        }

        // 分离路径中的查询参数部分，只处理路径本身
        String pathOnly = apiPath.contains("?") ? apiPath.split("\\?", 2)[0] : apiPath;
        pathOnly = normalizeURLPath(pathOnly);

        String[] parts = pathOnly.split("/");
        List<String> pathParameterList = new ArrayList<>();
        List<String> optionalPathParameterList = new ArrayList<>();
        StringBuilder regexBuilder = new StringBuilder("^");

        boolean hasOptional = false;

        for (String part : parts) {
            if (part.isEmpty()) continue;

            // 检查是否为可选参数 {param?}
            Matcher optionalMatcher = OPTIONAL_PARAM_PATTERN.matcher(part);
            if (optionalMatcher.find()) {
                String paramName = optionalMatcher.group(1);
                optionalPathParameterList.add(paramName);
                regexBuilder.append("(?:/([^/]+))?");
                hasOptional = true;
                continue;
            }

            // 检查当前部分是否包含必需参数
            Matcher matcher = PARAM_PATTERN.matcher(part);
            if (matcher.find()) {
                String paramName = matcher.group(1);
                pathParameterList.add(paramName);
                regexBuilder.append("/([^/]+)");
            } else {
                regexBuilder.append("/").append(Pattern.quote(part));
            }
        }

        // 统一处理路径结尾的斜杠，忽略后续的查询参数
        regexBuilder.append("/?(?:\\?.*)?$");

        Pattern pathPattern = Pattern.compile(regexBuilder.toString());

        return new PathInfo(
            contextPath,
            pathOnly,
            pathParameterList,
            optionalPathParameterList,
            queryParameterList2Map(queryParameterList),
            pathPattern,
            hasOptional
        );
    }

    public static Map<String, QueryParameter> queryParameters2Map(QueryParameter... queryParameters) {
        return queryParameterList2Map(Arrays.asList(queryParameters));
    }

    public static Map<String, QueryParameter> queryParameterList2Map(List<QueryParameter> queryParameterList) {
        return queryParameterList.stream()
            .collect(
                Collectors.toMap(
                    QueryParameter::getName,
                    queryParameter -> queryParameter,
                    (existing, replacement) -> existing // 处理重复参数名的情况
                )
            );
    }

    /**
     * 标准化URL路径
     * 移除协议、主机和查询参数，确保路径格式统一
     */
    public static String normalizeURLPath(String urlPath) {
        if (urlPath == null || StringUtil.isBlank(urlPath)) {
            return "";
        }

        String path = urlPath.trim();

        // 移除协议和主机部分（如http://localhost:8080）
        if (path.startsWith("http://") || path.startsWith("https://")) {
            int startIndex = path.startsWith("http://") ? 7 : 8;
            int slashIndex = path.indexOf('/', startIndex);
            if (slashIndex != -1) {
                path = path.substring(slashIndex);
            } else {
                path = "/"; // 无效URL，默认为根路径
            }
        }

        // 移除查询参数部分
        int queryIndex = path.indexOf('?');
        if (queryIndex != -1) {
            path = path.substring(0, queryIndex);
        }

        // 确保路径以/开头
        if (!path.startsWith("/")) {
            path = "/" + path;
        }

        // 移除末尾的斜杠（根路径除外）
        if (path.length() > 1 && path.endsWith("/")) {
            path = path.substring(0, path.length() - 1);
        }

        return path;
    }

    /**
     * 设置上下文路径
     */
    public void setContextPath(String contextPath) {
        this.contextPath = normalizeURLPath(contextPath);
    }

    /**
     * 获取API路径
     */
    public String getAPIPath() {
        return this.apiPath;
    }

    /**
     * 获取完整的路径
     */
    public String getFullPath() {
        if (
            StringUtil.isBlank(this.contextPath) ||
            this.contextPath.equals("/")
        ) {
            return this.apiPath;
        }
        return this.contextPath + this.apiPath;
    }

    /**
     * 获取路径参数列表
     */
    public List<String> getPathParameterList() {
        return new ArrayList<>(pathParameterList);
    }

    /**
     * 获取可选路径参数列表
     */
    public List<String> getOptionalPathParameterList() {
        return new ArrayList<>(optionalPathParameterList);
    }

    /**
     * 获取查询参数名称列表
     */
    public String[] getQueryParameterNames() {
        return queryParameterMap.keySet().toArray(new String[0]);
    }

    /**
     * 获取查询参数名称列表
     */
    public List<String> getQueryParameterNameList() {
        return new ArrayList<>(queryParameterMap.keySet());
    }

    /**
     * 获取查询参数列表
     */
    public List<QueryParameter> getQueryParameterList() {
        return new ArrayList<>(queryParameterMap.values());
    }

    /**
     * 获取查询参数映射
     */
    public Map<String, QueryParameter> getQueryParameterMap() {
        return queryParameterMap;
    }

    /**
     * 获取查询参数
     */
    public QueryParameter getQueryParameter(String name) {
        return queryParameterMap.get(name);
    }

    /**
     * 判断路径是否包含可选参数
     */
    public boolean hasOptionalParameters() {
        return hasOptionalParams;
    }

    /**
     * 检查给定路径是否匹配当前API路径模式
     * 支持包含查询参数的路径匹配
     */
    public boolean matches(String fullPath) {
        if (fullPath == null) return false;
        return pathPattern.matcher(fullPath).matches();
    }

    /**
     * 从路径中提取路径参数（包括可选参数）
     * 忽略查询参数部分，只处理路径
     */
    public Map<String, Object> parsePathParameterMap(String fullPath) {
        // 只处理路径部分，忽略查询参数
        String path = fullPath.contains("?") ? fullPath.split("\\?", 2)[0] : fullPath;
        path = this.normalizeAPIPath(path);

        Map<String, Object> pathParameterMap = new HashMap<>();
        Matcher matcher = pathPattern.matcher(path);

        if (matcher.matches()) {
            int groupIndex = 1;

            // 处理必需参数
            for (String parameterName : pathParameterList) {
                if (groupIndex <= matcher.groupCount()) {
                    String parameterValue = matcher.group(groupIndex);
                    pathParameterMap.put(parameterName, parameterValue != null ? parameterValue : "");
                    groupIndex++;
                }
            }

            // 处理可选参数
            for (String parameterName : optionalPathParameterList) {
                if (groupIndex <= matcher.groupCount()) {
                    String parameterValue = matcher.group(groupIndex);
                    if (parameterValue != null) {
                        pathParameterMap.put(parameterName, parameterValue);
                    }
                    groupIndex++;
                }
            }
        }
        return pathParameterMap;
    }

    /**
     * 从路径中提取查询参数
     * 专门处理?后面的查询字符串
     */
    public Map<String, Object> parseQueryParameterMap(String fullPath) {
        Map<String, Object> queryParamMap = new HashMap<>();

        if (fullPath == null) {
            return queryParamMap;
        }

        // 查找 '?' 的位置，只处理查询部分
        int queryIndex = fullPath.indexOf('?');
        if (queryIndex == -1 || queryIndex == fullPath.length() - 1) {
            return queryParamMap; // 没有查询参数或查询参数为空
        }

        String queryString = fullPath.substring(queryIndex + 1);

        // 拆分键值对，支持&和;作为分隔符
        String[] pairs = queryString.split("[&;]");
        for (String pair : pairs) {
            if (pair.isEmpty()) continue;

            int eqIndex = pair.indexOf('=');
            String key;
            String value;

            if (eqIndex != -1) {
                key = decodeURIComponent(pair.substring(0, eqIndex));
                value = decodeURIComponent(pair.substring(eqIndex + 1));
            } else {
                key = decodeURIComponent(pair);
                value = "";
            }

            // 处理多值参数，保持参数顺序
            if (queryParamMap.containsKey(key)) {
                Object existing = queryParamMap.get(key);
                if (existing instanceof List) {
                    ((List<String>) existing).add(value);
                } else {
                    List<String> list = new ArrayList<>();
                    list.add(existing.toString());
                    list.add(value);
                    queryParamMap.put(key, list);
                }
            } else {
                queryParamMap.put(key, value);
            }
        }

        return queryParamMap;
    }

    /**
     * 同时提取路径参数和查询参数
     * 对于/api/v1/article/page/2?pageSize=5这样的路径，会同时返回
     * {page: "2", pageSize: "5"}
     */
    public Map<String, Object> parseAllParameters(String fullPath) {
        Map<String, Object> allParams = new HashMap<>();

        // 合并路径参数
        allParams.putAll(this.parsePathParameterMap(fullPath));

        // 合并查询参数
        allParams.putAll(this.parseQueryParameterMap(fullPath));

        return allParams;
    }

    /**
     * 标准化路径，移除上下文路径前缀并确保以斜杠开头
     */
    private String normalizeAPIPath(String fullPath) {
        if (fullPath == null) return "";

        // 1. 先移除协议和主机部分
        String path = normalizeURLPath(fullPath);

        // 2. 移除上下文路径
        if (contextPath != null && !contextPath.isEmpty() && path.startsWith(contextPath)) {
            path = path.substring(contextPath.length());
            // 确保路径仍然以/开头
            if (!path.startsWith("/")) {
                path = "/" + path;
            }
        }

        return path;
    }

    /**
     * URL 解码，处理+号为空格的情况
     */
    private String decodeURIComponent(String encoded) {
        try {
            // 处理表单编码中+表示空格的情况
            String decoded = URLDecoder.decode(encoded.replace("+", "%2B"),
                    StandardCharsets.UTF_8.name());
            // 替换可能的空格编码
            return decoded.replace("%20", " ");
        } catch (Exception e) {
            return encoded; // 解码失败时返回原始值
        }
    }

    /**
     * 获取上下文路径
     */
    public String getContextPath() {
        return this.contextPath;
    }

    /**
     * 获取完整的正则表达式模式
     */
    public Pattern getPathPattern() {
        return this.pathPattern;
    }

    @Override
    public String toString() {
        return "PathInfo{" +
            "contextPath='" + contextPath + '\'' +
            ", apiPath='" + apiPath + '\'' +
            ", pathParameterList=" + pathParameterList +
            ", optionalPathParameterList=" + optionalPathParameterList +
            ", hasOptionalParams=" + hasOptionalParams +
            ", pathPattern=" + pathPattern +
            '}';
    }

    /**
     * 构建器模式支持
     */
    public static class Builder {
        private String contextPath = "";
        private String apiPath;
        private List<QueryParameter> queryParameterList = new ArrayList<>();

        /**
         * 设置apiPath
         */
        public Builder apiPath(String apiPath) {
            this.apiPath = apiPath;
            return this;
        }

        /**
         * 设置contextPath
         */
        public Builder contextPath(String contextPath) {
            this.contextPath = contextPath;
            return this;
        }

        /**
         * 设置查询参数列表
         */
        public Builder queryParameters(List<QueryParameter> queryParameters) {
            this.queryParameterList = queryParameters;
            return this;
        }

        /**
         * 添加查询参数
         */
        public Builder addQueryParameter(String name) {
            return this.addQueryParameter(new QueryParameter(name));
        }

        /**
         * 添加查询参数
         */
        public Builder addQueryParameter(QueryParameter parameter) {
            if (this.queryParameterList == null) {
                this.queryParameterList = new ArrayList<>();
            }
            this.queryParameterList.add(parameter);
            return this;
        }

        /**
         * 添加多个查询参数
         */
        public Builder addQueryParameters(String... names) {
            return this.addQueryParameters(
                Arrays
                    .stream(names)
                    .map(QueryParameter::new)
                    .toArray(QueryParameter[]::new)
            );
        }

        /**
         * 添加多个查询参数
         */
        public Builder addQueryParameters(QueryParameter... parameters) {
            if (this.queryParameterList == null) {
                this.queryParameterList = new ArrayList<>();
            }
            if (parameters != null && parameters.length > 0) {
                this.queryParameterList.addAll(Arrays.asList(parameters));
            }
            return this;
        }

        /**
         * 构建PathInfo实例
         */
        public PathInfo build() {
            if (apiPath == null) {
                throw new IllegalStateException("API path must be set");
            }
            return PathInfo.fromAPIPath(apiPath, contextPath, queryParameterList);
        }
    }

    /**
     * 创建PathInfo构建器
     */
    public static Builder builder() {
        return new Builder();
    }
}
